class Tracer:
    def __init__(self, func):
        self.calls = 0
        self.func = func

    def __call__(self, *args):
        self.calls += 1
        print('call {} to {}'.format(self.calls, self.func.__name__))
        self.func(*args)


@Tracer  # same as spam = tracer(spam)
def spam(a, b, c):  # wrap spam in a decorator object
    print(a, b, c)


spam(1, 2, 3)  # really calls the tracer wrapper object
spam('a', 'b', 'c')  # invokes __call__ in class
spam(4, 5, 6)  # __call__ adds logic and runs original object
